/**
 * Copyright (c) 2007, Blue Hole Software. All rights reserved.
 * Code licensed under the Apache 2.0 License:
 * http://www.apache.org/licenses/
 */
package org.bhf.security.common;

import javax.security.auth.Subject;
import java.io.Serializable;
import java.util.Set;


/**
 * Public credential for a Login IDuser's Group. Each authenticated <code>Subject</code> carries a <code>Group</code>
 * as a public credential. It is important not to confuse Groups and Roles. Roles are the means by which a set of
 * Users are granted common permissions. Groups define a set of Users for the purposes of managing those Users. Some
 * security systems use groups as a way to grant common permissions. That is not the case in the BHF. To grant common
 * permissions, use Roles instead.
 */
public final class Group implements Serializable
{
    private static final long           serialVersionUID    = 7930732926638008763L;
    private static final Class<Group>   THIS_CLASS          = Group.class;

    private final String name;

    /**
     * Create a <code>Group</code> credential with the given name.
     *
     * @param name the Group name.  Must not be <code>null</code>.
     *
     * @throws IllegalArgumentException if <code>name == null</code>.
     */
    public Group( final String name )
    {
        if( name == null )
            throw new IllegalArgumentException( "name == null" );

        this.name = name;
    }

    /**
     * Returns the name of this <code>Group</code>.
     *
     * @return the name of this <code>Group</code>.
     */
    public String           getName()
    {
        return name;
    }

    /**
     * Convenience method to return the <code>Group</code> in a
     * <code>Subject</code>.
     *
     * @param subject The <code>Subject</code> from which to extract the
     *      <code>Group</code>.  Must not be <code>null</code>.
     * @return The <code>Group</code> of the given <code>Subject</code>
     * @throws IllegalArgumentException if <code>subject == null</code>
     *      or if <code>subject</code> does not contain exactly one
     *      <code>Group</code> as a public credential.
     */
    public static Group     getGroup( final Subject subject )
    {
        if( subject == null )
            throw new IllegalArgumentException( "subject == null" );

        final Set<Group> set = subject.getPublicCredentials( THIS_CLASS );

        if( set.size() != 1 )
            throw new IllegalArgumentException( "subject.getPublicCredentials( Group.class ).size() != 1" );

        return set.iterator().next();
    }

    /**
     * Convenience method to return the <code>Group</code> of the
     * <code>Subject</code> associated with the current thread.
     *
     * @return The <code>Group</code> of the contextual <code>Subject</code>
     * @throws IllegalArgumentException if <code>subject</code> does not
     *      contain exactly one <code>Group</code> as a public credential
     *      or if there is no code>Subject</code> associated with the
     *      current thread.
     */
    public static Group      getGroup()
    {
        return getGroup( ContextSubject.getContextSubject() );
    }

    /**
     * Equality based on name
     * @param o An object, possibly <code>null</code>
     * @return <code>true</code> if equal
     */
    public boolean equals( final Object o )
    {
        return this == o || !(o == null || getClass() != o.getClass()) && name.equals( ((Group) o).name );
    }

    /**
     * Equality based on name
     * @return Hash
     */
    public int hashCode()
    {
        return name.hashCode();
    }
}